package utils;

/**
 * 数学工具类
 *
 * @author liangfuqiang
 * @since 2023-03-14
 */
public class MathUtil {

    public static double randomRange(double from, double to) {
        return (Math.random() * (to - from)) + from;
    }

    public static double sigmoid(double x) {
        return 1 / (1 + Math.exp(-x));
    }

    /**
     * 矩阵*矩阵
     *
     * @param d1 矩阵1
     * @param d2 矩阵2
     * @return 新的矩阵
     */
    public static double[][] matrixMultiply(double[][] d1, double[][] d2) {
        int a = d1.length, b = d1[0].length, c = d2.length, d = d2[0].length;
        if (b != c) {
            throw new RuntimeException("d1's cols must be equal to d2's rows");
        }
        double[][] res = new double[a][d];
        for (int i = 0; i < res.length; i++) {
            for (int j = 0; j < res[i].length; j++) {
                res[i][j] = calculate(d1[i], d2, j);
            }
        }
        return res;
    }

    private static double calculate(double[] d1, double[][] d2, int col) {
        double res = 0;
        for (int i = 0; i < d1.length; i++) {
            res += d1[i] * d2[i][col];
        }
        return res;
    }


    /**
     * 矩阵*常数
     *
     * @param d1 矩阵1
     * @param d2 常数
     * @return d1
     */
    public static double[][] matrixMultiply(double[][] d1, double d2) {
        int a = d1.length, b = d1[0].length;

        for (int i = 0; i < a; i++) {
            for (int j = 0; j < b; j++) {
                d1[i][j] *= d2;
            }
        }
        return d1;
    }

    /**
     * 矩阵+矩阵
     *
     * @param d1 矩阵1
     * @param d2 矩阵2
     * @return d1
     */
    public static double[][] matrixPlus(double[][] d1, double[][] d2) {
        int a = d1.length, b = d1[0].length, c = d2.length, d = d2[0].length;
        if (a != c || b != d) {
            throw new RuntimeException("d1, d2 must have same shape");
        }
        for (int i = 0; i < a; i++) {
            for (int j = 0; j < b; j++) {
                d1[i][j] += d2[i][j];
            }
        }
        return d1;
    }

    /**
     * 矩阵转置
     *
     * @param d1 矩阵1
     * @return result
     */
    public static double[][] matrixTrans(double[][] d1) {
        int a = d1.length, b = d1[0].length;

        double[][] res = new double[b][a];
        for (int i = 0; i < res.length; i++) {
            for (int j = 0; j < res[i].length; j++) {
                res[i][j] = d1[j][i];
            }
        }
        return res;
    }

    /**
     * 将矩阵每行第一个数设为sigmoid
     *
     * @param d1 矩阵1
     */
    public static void setSigmoid(double[][] d1) {
        for (int i = 0; i < d1.length; i++) {
            d1[i][0] = sigmoid(d1[i][0]);
        }
    }

    public static void changeWight(double[][] delta, double[][] output, double[][] preRes, double alpha, double[][] wight) {
        for (int i = 0; i < delta.length; i++) {
            delta[i][0] = delta[i][0] * output[i][0] * (1 - output[i][0]);
        }
        matrixPlus(wight, matrixMultiply(matrixMultiply(delta, matrixTrans(preRes)), alpha));
    }
}
